package gsgin

import (
	"fmt"
	"gitee.com/Sxiaobai/gs/gstool"
	"github.com/gin-gonic/gin"
	"sync"
	"time"
)

type TSse struct {
	SseList map[string]*Sse
	lock    sync.RWMutex
}

type Event struct {
	EventId    string
	Msg        string
	DelayMills int
}

type Sse struct {
	ClientId           string           //链接ID
	StopC              chan int         //控制gin接口是否退出
	C                  *gin.Context     //c gin
	ChanList           *gstool.ChanList //消息通道
	registerMillSecond int64            //注册时间 毫秒时间戳
	lastEventId        string           //最后发送的eventId
}

func (h *TSse) Register(clientId string, stopC chan int, c *gin.Context) *Sse {
	sse := h.GetSseByClientId(clientId)
	if sse != nil {
		sse.C = c
		sse.StopC = stopC
		sse.ChanList.Active()
		return sse
	}
	chanList := &gstool.ChanList{}
	chanList.Init(10000, func(msg any) error {
		return h.sendMsg(msg.(*Event), sse)
	})
	sse = &Sse{
		ClientId:           clientId,
		StopC:              stopC,
		C:                  c,
		ChanList:           chanList,
		registerMillSecond: time.Now().UnixMilli(),
	}
	h.lock.Lock()
	defer h.lock.Unlock()
	h.SseList[clientId] = sse
	return sse
}

func (h *TSse) sendMsg(e *Event, sse *Sse) (returnErr error) {
	defer func() {
		if err := recover(); err != nil {
			returnErr = gstool.Error(`%s 发送失败 %s`, sse.ClientId, err)
		}
	}()
	if e.DelayMills > 0 {
		time.Sleep(time.Millisecond * time.Duration(e.DelayMills))
	}
	sendMsg := fmt.Sprintf("id: %s\n%s\n\n", e.EventId, e.Msg)
	_, err := sse.C.Writer.Write([]byte(sendMsg))
	if err != nil {
		returnErr = gstool.Error(`%s 写入失败 %s %s`, sse.ClientId, sendMsg, err.Error())
		return
	} else {
		sse.C.Writer.Flush()
		sse.lastEventId = e.EventId
	}
	return
}

func (h *TSse) Send(clientId, msg string, delayMills int) error {
	sse := h.GetSseByClientId(clientId)
	if sse == nil { //创建一个绑定的 内容为空
		sse = h.Register(clientId, nil, nil)
	}
	sse.registerMillSecond += 1
	return sse.ChanList.AddMsg(&Event{
		EventId:    fmt.Sprintf(`%s_%d`, clientId, sse.registerMillSecond),
		Msg:        msg,
		DelayMills: delayMills,
	})
}

func (h *TSse) Pause(sse *Sse) {
	sse.ChanList.Pause()
}

func (h *TSse) UnRegister(clientId string) {
	h.lock.Lock()
	h.lock.Unlock()
	delete(h.SseList, clientId)
}

func (h *TSse) CleanMsg(clientId string) {
	sse := h.GetSseByClientId(clientId)
	if sse == nil {
		return
	}
	h.Pause(sse)
	sse.ChanList.Stop()
	chanList := &gstool.ChanList{}
	chanList.Init(10000, func(msg any) error {
		return h.sendMsg(msg.(*Event), sse)
	})
	sse.ChanList = chanList
}

func (h *TSse) GetSseByClientId(clientId string) *Sse {
	h.lock.Lock()
	h.lock.Unlock()
	if sse, ok := h.SseList[clientId]; ok {
		return sse
	}
	return nil
}
